/*
   andrew
   2012-08-19
 */
#include "mem_pool.h"


namespace andrew
{
	namespace tools
	{
		namespace mem
		{
			//
			mem_pool::mem_pool():ptr_mem_pool(NULL),
					ptr_bit_map(NULL),
					ptr_mem_mgr(NULL),
					b_inited (MEM_POOL_INIT_NO)
			{
			}
			mem_pool::~ mem_pool()
			{
				if(NULL != ptr_mem_pool)
				{
					delete ptr_mem_pool;
					ptr_mem_pool = NULL;
				}
				if(NULL != ptr_bit_map)
				{
					delete ptr_bit_map;
					ptr_bit_map = NULL;
				}
				if(NULL != ptr_mem_mgr)
				{
					delete ptr_mem_mgr;
					ptr_mem_mgr = NULL;
				}
			}
			int mem_pool::init(size_t _tmp_max_mem_size,size_t _tmp_chunk_size)
			{

				chunk_size = _tmp_chunk_size;
				if(0 == chunk_size)
				       chunk_size = MEM_POOL_DEFAULT_CHUNK_SIZE;	
				max_mem_size = _tmp_max_mem_size;	
				if(0 == max_mem_size)
					max_mem_size = MEM_POOL_DEFAULT_MEM_SIZE;
				ptr_mem_pool = (char*)malloc(max_mem_size * sizeof(char));
				if(NULL == ptr_mem_pool)
				{
					return ERROR;
				}
				//init bit map
				used_count = 0;
				chunk_count = (max_mem_size / chunk_size);
				free_count = chunk_count;
				bit_map_size = ((chunk_count + 7) >> 3) + 1;
				ptr_bit_map = (char*)malloc(bit_map_size * sizeof(char));
				if(NULL == ptr_bit_map)
				{
					return ERROR;
				}
				memset(ptr_bit_map,0,bit_map_size * sizeof(char));
				//set the remain bits used = 1
				unsigned int _rmain_bits = bit_map_size * 8 - chunk_count;
				unsigned int _rmain_bits_bytes = chunk_count / 8;
				unsigned int _rmain_bits_bits = chunk_count % 8;
				char *ptr = ptr_bit_map + _rmain_bits_bytes;
				//set ptr
				*ptr = 0xFF >> _rmain_bits_bits;
				ptr ++;
				while(ptr <ptr_bit_map + bit_map_size)
					*ptr++ = 0xFF;
				ptr = NULL;
				//init mem manager
				/*
				if(ERROR == initMemMgr())
					return ERROR;
					*/

				b_inited = MEM_POOL_INIT_YES;
				return OK;
			}
			int mem_pool::initMemMgr()
			{
				ptr_mem_mgr = new mem_manager();
				ptr_mem_mgr->mem_idx = 0;
				ptr_mem_mgr->used_size = 0;
				ptr_mem_mgr->free_size = chunk_size;
			        ptr_mem_mgr->ptr_next = NULL;	
				//mem_manager *ptr_orgin = NULL;
				mem_manager *ptr = NULL;
				for(size_t i = 0; i < chunk_count; ++i)
				{

					ptr = new mem_manager();
					ptr->mem_idx = i;
					ptr->used_size = 0;
					ptr->free_size = chunk_size;
					ptr->ptr_next = NULL;

					

				}
				return OK;
			}
			char *mem_pool::alloc(size_t _tmp_alloc_size)
			{

				if(MEM_POOL_INIT_NO == b_inited)
					return NULL;
				char* ptr = NULL;
				unsigned char _tmp_chunk_alloc_count;
				unsigned int _tmp_size = (_tmp_alloc_size + 7)/ chunk_size;
				if(_tmp_size > MEM_POOL_MAX_ALLOC_CHUNK_COUNT)
					return NULL;
				else
					_tmp_chunk_alloc_count = (char)_tmp_size;
				char* ptr_tmp_map = ptr_bit_map;
				unsigned int bytes_size = _tmp_size / 8;
				unsigned int remain_bits_size =  _tmp_size % 8;
				unsigned int _tmp_find_count = 0;
				char* ptr_tmp = NULL;
				bool bfind = false;
				unsigned char _dchar = 0xFF >> remain_bits_size;
				unsigned char _move_bits = 0;
				for(;ptr_tmp_map < ptr_bit_map + bit_map_size ;ptr_tmp_map ++)
				{
					ptr_tmp = ptr_tmp_map;
					while(_tmp_find_count < bytes_size
							&& *ptr_tmp == 0)
					{
						_tmp_find_count ++;
						ptr_tmp ++;	
					}
					if(_tmp_find_count < bytes_size)
					{
						_tmp_find_count  = 0;
						cout<<"continue 1"<<endl;
						continue;
					}
					if(0 == bytes_size)
					{
						unsigned char _tchar = *ptr_tmp;
						for(int i = 0;i< 8 - remain_bits_size;i++)
						{
							if(_tchar > _dchar)
								_tchar <<= 1;
							else //find one
							{
								bfind = true;
								_move_bits = i;
								cout<<i<<endl;
								//ptr_tmp_map += i;
								break;

							}
						}

					}
					//else find fit the bytes,then find the bit
					else
					{
						if(*ptr_tmp > _dchar) 
						{
							_tmp_find_count  = 0;
							cout<<"continue 2"<<endl;
							continue;
						}
						else
							bfind = true;
					}
					if(bfind == true)	
					{
						unsigned int idx = (ptr_tmp_map - ptr_bit_map) << 3; 
						//candidate find
						//set the bytes 1
						if(0 != bytes_size)
						{
							for(;ptr_tmp_map<ptr_tmp;ptr_tmp_map ++)
							{
								*ptr_tmp_map = 0xFF;
							}	
						}
						//set the remain bits
						unsigned char _tmp_move = 0xFF <<(8 - remain_bits_size);
						_tmp_move >>= _move_bits;
						*ptr_tmp_map ^= _tmp_move;
						ptr = ptr_mem_pool + idx;
						hs_map_ptrs.insert(pair<unsigned int,unsigned int>(*(unsigned int*)&ptr,_tmp_alloc_size));
						cout<<"alloc:"<<*(unsigned int*)&ptr<<endl;
						break;
					}
				}
				ptr_tmp_map = NULL;
				ptr_tmp = NULL;

				return ptr;
			}
			int mem_pool::release(char* _ptr_mem)
			{
				
				cout<<"release:"<<*(unsigned int*)&_ptr_mem<<endl;
				if(MEM_POOL_INIT_NO == b_inited)
					return ERROR;
				unordered_map<unsigned int,unsigned int >::iterator it;
				it = hs_map_ptrs.find(*(unsigned int*)&_ptr_mem);
				if(it == hs_map_ptrs.end())
				{
					cout<<"free ptr not found"<<endl;
					return ERROR;
				}
				else
				{
					unsigned int _tmp_size = it->second;
					unsigned int idx =(unsigned int)( _ptr_mem - ptr_mem_pool);
					unsigned int bytes_size = _tmp_size / 8;
					unsigned int remain_bits_size =  _tmp_size % 8;
					char *ptr = NULL;
					for(ptr = ptr_mem_pool + idx;
							ptr && ptr < (bytes_size + ptr_mem_pool +idx);
							++ ptr)
					{
						*ptr = 0x00;

					}
					char c =(0xFF >> remain_bits_size);  
					*ptr &= c;
					ptr = NULL;
					hs_map_ptrs.erase(*(unsigned int*)_ptr_mem);
					cout<<"size ="<<hs_map_ptrs.size()<<endl;
					cout<<"erase ok"<<endl;
				}

				return OK;
			}


		}
	}
}
